function Promise(executor) {
  let self = this;
  self.status = 'pending';
  self.value = undefined;
  self.reason = undefined;
  self.onResolvedCallbacks = [];
  self.onRejectedCallbacks = [];

  function resolve(value) {
    if (self.status === 'pending') {
      self.value = value;
      self.status = 'resolved';
      self.onResolvedCallbacks.forEach(fn => fn());
    }


  }

  function reject(reason) {
    if (self.status === 'pending') {
      self.reason = reason;
      self.status = 'rejected';
      self.onRejectedCallbacks.forEach(fn => fn());
    }

  }

  try {
    executor(resolve, reject);//用户会调用resolve 或者reject

  } catch (e) {
    reject(e);
  }

}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'));
  }
  let called;//表示当前有没有被调用过
  if ((x != null && typeof x === 'object') || typeof x === 'function') {
    try {
      let then = x.then;
      if (typeof then === 'function') {
        then.call(x, (y) => {
          // resolve(y);
          if (called) return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }, (r) => {
          if (called) return;
          reject(r);
        });
      } else {
        resolve(x);
      }
    } catch (e) {//防止别人的库即调用了成功又调用了失败
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

Promise.prototype.then = function (onFullFilled, onRejected) {
  onFullFilled = typeof onFullFilled === 'function' ? onFullFilled : value => value;
  onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
    throw err;
  }
  let self = this;

  let promise2 = new Promise(function (resolve, reject) {


    if (self.status === 'resolved') {
      setTimeout(() => {
        try {
          let x = onFullFilled(self.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      }, 0);

    }
    if (self.status === 'rejected') {
      setTimeout(() => {
        try {
          let x = onRejected(self.reason);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      }, 0);

    }
    if (self.status === 'pending') {
      self.onResolvedCallbacks.push(function () {
        setTimeout(() => {
          try {
            let x = onFullFilled(self.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      });
      self.onRejectedCallbacks.push(function () {
        setTimeout(() => {
          try {
            let x = onRejected(self.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      });

    }
  });

  return promise2;

}

Promise.defer = function () {
  let dfd = {};

  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
}
Promise.all = function(values){
  return new Promise((resolve,reject)=>{
    let arr=[];//最终结果
    let index = 0;
    function processData(key, value) {
      index++;
      arr[key]=value;
      if (index===values.length){
        resolve(arr);
      }
    }
    for (let i=0;i<values.length;i++){
      let current=values[i];
      if (current&&current.then && typeof current.then=='function'){
        current.then(y=>{
          processData(i,y);
        },reject);
      }else {
        processData(i,current);
      }
    }
  })
}
Promise.race = function(values){
  return new Promise((resolve,reject)=>{

    for (let i=0;i<values.length;i++){
      let current=values[i];
      if (current&&current.then && typeof current.then=='function'){
        current.then(resolve,reject);
      }else {
        resolve(current);
      }
    }
  })
}

Promise.resolve=function(){
  return new Promise((resolve,reject)=>{
    resolve();
  })
}
Promise.reject=function(){
  return new Promise((resolve,reject)=>{
    reject();
  })
}
//promise-aplus-tests
//bluebird
module.exports = Promise;
